/*
	Copyright (c) 2009, SpLib.net
  	All rights reserved.
  	
  	Author:6spring
  	About:BaseObj 提供Event的注册/分发，Module对象的树形递归支持
*/

package SpLib.ObjSys
{
	import SpLib.Com.Com;
	import SpLib.Com.EveNode;
	import SpLib.Com.SpLibEvent;
	import SpLib.Com.Str2Key;
	import SpLib.Tools.Tr;
	import SpLib.std.iterator;
	import SpLib.std.map;
	
	import flash.events.EventDispatcher;
	import flash.system.ApplicationDomain;
	import flash.utils.getDefinitionByName;
	
	public class BaseObj extends EventDispatcher
	{	
		private static var s_ObjFactory:SpLib.std.map = new SpLib.std.map();
		
		private var m_Father:BaseObj = null;
		
		private var m_ChildNum:int = 0;
		private var m_nSubObjSeed:int = 0;
		private var m_ChildHead:BaseObj = null;
		private var m_ChildTail:BaseObj = null;
		
		private var m_PrevObj:BaseObj = null;
		private var m_NextObj:BaseObj = null;
		private var m_nObjIdx:int = -1;
			
		private var m_bDeled:Boolean = false;
		private var m_EveMap:SpLib.std.map = null;
		private var m_szModule:SpLib.std.map = null;
		
		public static function AddObjFactory(classname:String,regclass:Class):Boolean
		{
			return s_ObjFactory.insert(classname,regclass);
		}
		
		public static function CreateObj(classname:String,f:BaseObj):SpLib.ObjSys.BaseObj
		{
			var regclass:Class;
			
			var iter:SpLib.std.iterator = s_ObjFactory.find(classname);
			if(iter!=s_ObjFactory.end())
			{
				regclass = iter.m_Data as Class;
				return _CreateObjAsClass(regclass,f);
			}
			
			var domain : ApplicationDomain = ApplicationDomain.currentDomain;
			if(domain.hasDefinition(classname))
			{
				regclass = getDefinitionByName(classname) as Class; 
				if(regclass!=null)
				{
					return _CreateObjAsClass(regclass,f);
				}
			}
			
			return null;
		}
		
		private static function _CreateObjAsClass(classname:Class,f:BaseObj):SpLib.ObjSys.BaseObj
		{
			var retobj:BaseObj = new classname(f) as BaseObj;
			return retobj;
		}
		
		public function BaseObj(f:BaseObj)
		{
			super();
			
			if(f!=null)
			{
				f.AddSubObj(this);
			}
			
			RegEvent("DelThis",EVE_DelThis);
			RegEvent("DoCmd",EVE_DoCmd);
		}
		
		protected function RegEvent(evename:String,func:Function):void
		{
			if(m_EveMap==null)
			{
				m_EveMap = new SpLib.std.map();
			}
			
			var evefullname:String = "SpLibObjEvent_" + evename;
			var eve:SpLib.Com.EveNode = new SpLib.Com.EveNode(evename,func)
			var eveid:uint = SpLib.Com.Str2Key(evename);
			var iter:SpLib.std.iterator = m_EveMap.find(eveid);
			if(iter!=null)
			{
				var oldeve:SpLib.Com.EveNode = iter.m_Data as SpLib.Com.EveNode;
				removeEventListener(evefullname,oldeve.m_Func);
			}
			
			m_EveMap.setvalue(eveid,eve);
				
			addEventListener(evefullname,func);
		}
		
		public function GetEveName(eveid:uint):String
		{
			var evenode:SpLib.std.iterator = m_EveMap.find(eveid);
			if(evenode!=null) 
			{
				var eve:SpLib.Com.EveNode = evenode.m_Data as SpLib.Com.EveNode;
				return eve.m_sEvename;
			}
			
			return "";
		}
		
		public function EventAsID(eveid:uint,agv:Array = null):void
		{
			if(!m_bDeled)
			{
				if(m_EveMap==null)
				{
					return;
				}
				
				var evenode:SpLib.std.iterator = m_EveMap.find(eveid);
				if(evenode!=null) 
				{
					var eve:SpLib.Com.EveNode = evenode.m_Data as SpLib.Com.EveNode;
					var evefullname:String = "SpLibObjEvent_" + eve.m_sEvename;
					dispatchEvent(new SpLibEvent(evefullname,eve.m_sEvename,agv));
				}
				else
				{
					SpLib.Tools.Tr.Warning("调用Event " + eveid + " 失败，Event不存在 - " +  SpLib.Com.Com.Array2Str(agv));
				}
			}
		}
		
		public function Event(eve:String,agv:Array = null):void
		{
			var eveid:uint = SpLib.Com.Str2Key(eve);
			EventAsID(eveid,agv);
		}
		
		protected function ClearEventMap():void
		{
			if(m_EveMap==null) return;
			
			var iter:SpLib.std.iterator = m_EveMap.begin();
			var evefullname:String;
			while(iter!=m_EveMap.end())
			{
				var oldeve:SpLib.Com.EveNode = iter.m_Data as SpLib.Com.EveNode;
				evefullname = "SpLibObjEvent_" + oldeve.m_sEvename;
				removeEventListener(evefullname,oldeve.m_Func);
				
				iter = iter.next;
			}
			m_EveMap.clear();
			
			m_EveMap = null;		
		}
		
		public function get deled():Boolean
		{
			return m_bDeled;
		}
		
		public function get father():BaseObj
		{
			return m_Father;
		}
		
		public function set father(f:BaseObj):void
		{
			if(m_Father==f) return;
			
			if(m_Father!=null)
			{
				m_Father.RemoveSubObj(this);
			}
			
			if(f!=null)
			{
				f.AddSubObj(this);
			}
		}
		
		public function get childhead():BaseObj
		{
			return m_ChildHead;
		}
		
		public function get childtail():BaseObj
		{
			return m_ChildTail;
		}
		
		public function get nextobj():BaseObj
		{
			return m_NextObj;
		}
		
		public function get prevobj():BaseObj
		{
			return m_PrevObj;
		}
		
		public function get childrennum():int
		{
			return m_ChildNum;
		}
		
		public function get objidx():int
		{
			return m_nObjIdx;
		}
		
		public function set objidx(id:int):void
		{
			m_nObjIdx = id;
		}
		
		public function get childseed():int
		{
			return m_nSubObjSeed;
		}
		
		public function GetChildByIdx(idx:int):BaseObj
		{
			var sub:BaseObj = m_ChildHead;
			while(sub!=null)
			{
				if(sub.m_nObjIdx==idx)
				{
					return sub;
				}
				
				sub = sub.nextobj;
			}
			
			return null;
		}
		
		private function AddSubObj(obj:BaseObj):void
		{
			if(m_ChildHead==null)
			{
				m_ChildHead = obj;
			}		
			
			if(m_ChildTail==null)
			{
				m_ChildTail = obj;
			}
			else
			{
				m_ChildTail.m_NextObj = obj;
				obj.m_PrevObj = m_ChildTail;
				
				m_ChildTail = obj;
			}
			
			obj.m_Father = this;
			obj.m_nObjIdx = m_nSubObjSeed++;
			m_ChildNum++;
			
			OnAddSubObj();
		}
		
		protected function OnAddSubObj():void
		{
			
		}
		
		private function RemoveSubObj(obj:BaseObj):void
		{
			if(m_ChildHead==obj)
			{
				m_ChildHead = obj.m_NextObj;
			}
			
			if(m_ChildTail==obj)
			{
				m_ChildTail = obj.m_PrevObj;
			}
			
			obj.UnlinkFahterObj();
			
			--m_ChildNum;
			
			OnRemoveSubObj();
		}
		
		protected function OnRemoveSubObj():void
		{
			
		}
		
		private function UnlinkFahterObj():void
		{
			if(m_PrevObj!=null)
			{
				m_PrevObj.m_NextObj = m_NextObj;
			}
			
			if(m_NextObj!=null)
			{
				m_NextObj.m_PrevObj = m_PrevObj;
			}
		
			m_NextObj = m_PrevObj = m_Father = null;
		}
		
		private function Unlinklist():void
		{
			m_NextObj = m_PrevObj = m_Father = null;
		}
		
		public function DelAllSub():void
		{
			var sub:BaseObj = m_ChildHead;
			var next:BaseObj;
			while(sub!=null)
			{
				next = sub.m_NextObj;
				sub.DelThis(false);
				sub.Unlinklist();
				sub = next;
			}
			
			m_ChildNum = 0;
			m_ChildHead = m_ChildTail = null;
			
			OnRemoveSubObj();
		}
		
		public function RegModule(mname:String,obj:BaseObj):Boolean
		{
			if(mname=="this" || mname=="father")
			{
				return false;
			}
			
			if(m_szModule==null)
			{
				m_szModule = new SpLib.std.map();
			}
			
			var iter:SpLib.std.iterator = m_szModule.find(mname);
			if(iter!=m_szModule.end())
			{
				var oldobj:BaseObj = iter.m_Data as BaseObj;
				if(oldobj.deled)
				{
					iter.m_Data = obj;
					return true;
				}
				
				return false;
			}
			
			
			return m_szModule.insert(mname,obj);
		}
		
		public function ReplaceModule(mname:String,obj:BaseObj):void
		{
			if(mname=="this" || mname=="pid" || mname=="father")
			{
				return;
			}
			
			if(m_szModule==null)
			{
				m_szModule = new SpLib.std.map();
			}
			
			m_szModule.setvalue(mname,obj);
		}
		
		public function UnRegModule(mname:String,obj:BaseObj):void
		{
			if(mname=="this" || mname=="pid" || mname=="father")
			{
				return;
			}
			
			if(m_szModule==null) return;
			
			var iter:SpLib.std.iterator = m_szModule.find(mname);
			if(iter!=m_szModule.end())
			{
				var oldobj:BaseObj = iter.m_Data as BaseObj;
				if(oldobj===obj)
				{
					m_szModule.erase(iter);
					return;
				}
			}
		}
		
		public function FindModule(mname:String):BaseObj
		{
			switch(mname)
			{
			case "this":
			{
				return this;
			}
			break;
			case "pid":
			case "father":
			{
				return m_Father;
			}
			break;
			}
			
			if(m_szModule!=null)
			{
				var iter:SpLib.std.iterator = m_szModule.find(mname);
				if(iter!=m_szModule.end())
				{
					var oldobj:BaseObj = iter.m_Data as BaseObj;
					if(oldobj.deled)
					{
						m_szModule.erase(iter);
						return null;
					}
					
					return oldobj;
				}
			}
			
			if(m_Father!=null)
			{
				return m_Father.FindModule(mname);
			}
			
			return null;
		}
		
		private function EVE_DoCmd(evt:SpLibEvent):void
		{
			var cmd:String,agv:Array;
			cmd = SpLib.Com.Com.GetArraySub(evt.m_Agv,0,"string","");
			agv = SpLib.Com.Com.GetArraySub(evt.m_Agv,1,"array",[]);
			if(cmd.length>0)
			{
				DoCmd(cmd,agv);
			}
		}
		
		public function DoCmd(cmd:String,agv:Array = null):void
		{
			 var module:String = "";
			 var evename:String = "";
			 var pos:int = cmd.indexOf(".");
			 if(pos<0)
			 {
			 	evename = cmd;
			 }
			 else
			 {
			 	module = cmd.substr(0,pos);
			 	cmd = cmd.substr(pos+1);
			 }
			 
			 if(module.length!=0)
			 {
			 	var obj:BaseObj = FindModule(module);
			 	if(obj!=null)
			 	{
			 		obj.DoCmd(cmd,agv);
			 	}
			 }
			 else
			 {
			 	Event(evename,agv);
			 }
		}
		
		private function EVE_DelThis(evt:SpLibEvent):void
		{
			DelThis();
		}
		
		public function DelThis(removefather:Boolean = true):void
		{
			if(m_bDeled==false)
			{
				OnDelThis();
				
				dispatchEvent(new SpLibEvent(SpLibEvent.OBJDELTHIS,"OnDelThis"));
				
				DelAllSub();
							
				ClearEventMap();
				
				if(m_szModule!=null)
				{
					m_szModule.clear();
					m_szModule = null;
				}
				
				if(removefather && m_Father!=null)
				{
					m_Father.RemoveSubObj(this);
				}
				
				m_Father = null;
				m_bDeled = true;
			}
		}
		
		protected function OnDelThis():void
		{
			
		}
	}
}